package com.xuanyue.db.xuan.core.index;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.xuanyue.db.xuan.core.exception.SQLException;
import com.xuanyue.db.xuan.core.table.IBitIndex;
import com.xuanyue.db.xuan.core.table.IColumn;
import com.xuanyue.db.xuan.core.table.ISortElement;
import com.xuanyue.db.xuan.core.table.expr.Expr;
import com.xuanyue.db.xuan.core.table.expr.ExprValue;
import com.xuanyue.db.xuan.core.table.expr.ExprValueType;
import com.xuanyue.db.xuan.core.table.expr.SortTemplate;
import com.xuanyue.db.xuan.msg.VLAUETYPE;
import com.xuanyue.db.xuan.msg.X2YValue;
/**
 * 
 *
 * @author 解观海
 * @email guanhaixie@sina.cn
 * @date 2020年12月27日
 *
 */
public class MapIndex implements IColumn{

	private Map<String,IColumn> data = new HashMap<>();
	private BitIndex mask = new BitIndex();
	private String path;
	
	private Map<String,IColumn> getData(){
		return data;
	}
	
	@Override
	public boolean modify(IColumn newOne,boolean cpDataFromOld) {
		MapIndex one = (MapIndex)newOne;
		Map<String,IColumn> res = new HashMap<>();
		for(String key:data.keySet()) {
			if(!one.getData().containsKey(key)) {
				new File(String.format("%s/%s", path,key)).delete();
			}else {
				data.get(key).modify(  one.getData().get(key),cpDataFromOld );
				res.put(key, data.get(key));
			}
		}
		for(String key:one.getData().keySet()) {
			if(!data.containsKey(key)) {
				one.getData().get(key).setPath(String.format("%s/%s", path,key));
				one.getData().get(key).init();
				one.getData().get(key).flush(mask.getMaxId());
				res.put(key, one.getData().get(key));
			}
		}
		this.data = res;
		return true;
	}
	
	public void addColumn(String name ,IColumn column) {
		data.put(name, column);
	}
	
	@Override
	public void setPath(String path) {
		this.path=path;
		data.forEach( (k,v)->{
			v.setPath(String.format("%s/%s", path,k));
		});
		mask.setPath(String.format("%s/mask",path));
	}

	@Override
	public void save() {
		for(IColumn c:data.values()) {
			c.save();
		}
		mask.save();
	}

	@Override
	public void load() {
		for(IColumn c:data.values()) {
			c.load();
		}
		mask.load();
	}

	@Override
	public boolean checkType(ExprValue v) {
		if(ExprValueType.MAP.is(v.getType())) {
			Map<String,ExprValue> m = v.getValue();
			
			for(Entry<String,ExprValue> en:m.entrySet()) {
				if(!data.containsKey(en.getKey())) {
					return false;
				}
				if(!data.get(en.getKey()).checkType(en.getValue())) {
					return false;
				}
			}
			return true;
		}else if(ExprValueType.NULL.is(v.getType())) {
			return true;
		}else {
			return false;
		}
	}

	@Override
	public void set(int rowId, ExprValue value) {
		if(ExprValueType.MAP.is(value.getType())) {
			Map<String,ExprValue> vl = value.getValue();
			for(Entry<String,IColumn> en:data.entrySet()) {
				if(vl.containsKey(en.getKey())) {
					en.getValue().set(rowId, vl.get(en.getKey()));
				}else {
					en.getValue().set(rowId, ExprValue.getNULLExprValue());
				}
			}
			mask.set(rowId);
		}else if(ExprValueType.NULL.is(value.getType())) {
			mask.set(rowId, false);
			for(Entry<String, IColumn> en:data.entrySet()) {
				en.getValue().set(rowId, value);
			}
//			data.forEach( (k,v)->{
//				v.set(rowId, value);
//			});
		}else {
			throw new SQLException("the value type mask be null or map");
		}
	}

	@Override
	public void saveRow(int rowId){
		
		for(Entry<String,IColumn> en:data.entrySet()) {
			en.getValue().saveRow(rowId);
		}
		mask.saveRow( rowId);
	}

	@Override
	public Map<String,Object> get(int rowId) {
		if(mask.get(rowId)) {
			Map<String,Object> r = new HashMap<>();
			for(Entry<String,IColumn> en:data.entrySet()) {
				r.put(en.getKey(), en.getValue().get(rowId));
			}
			return r;
		}
		return null;
	}

	@Override
	public ExprValue getExprValue(int rowId) {
		if(mask.get(rowId)) {
			Map<String,ExprValue> r = new HashMap<>();
			for(Entry<String,IColumn> en:data.entrySet()) {
				r.put(en.getKey(), en.getValue().getExprValue(rowId));
			}
			return new ExprValue(ExprValueType.MAP,r);
		}else {
			return ExprValue.getNULLExprValue();
		}
	}
	
	
	
	@Override
	public void flush(int maxId) {
		for(IColumn c:data.values()) {
			c.flush(maxId);
		}
		mask.flush(maxId);
		
	}

	@Override
	public int getDataSize() {
		int r=0;
		for(IColumn c:data.values()) {
			r+=c.getDataSize();
		}
		return r+1;
	}

	@Override
	public List<ISortElement> getSortE(SortTemplate sortTemplate) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean checkSortE(SortTemplate sortTemplate) {
		return sortTemplate.isType(SortTemplate.MAP);
	}

	@Override
	public VLAUETYPE getType() {
		return VLAUETYPE.MAP1STR2VALUE;
	}

	@Override
	public void init() {
		for(IColumn c:data.values()) {
			c.init();
		}
		mask.init();
	}

	@Override
	public void exe(Expr expr, List<IBitIndex> caches) {
		data.get(expr.getKey()).exe(expr,caches);
	}

	@Override
	public int checkAndContSource(Expr expr) {
		if(expr.getKey()==null||!data.containsKey(expr.getKey())) {
			return 0;
		}else {
			return data.get(expr.getKey()).checkAndContSource(expr);
		}
	}

}
